/*
 Copyright (C) 2013 Yuyao Liang

 This source code is release under the BSD License.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
 

 */
package com.googlecode.stereoplot;

/**
 * @author lianyuy
 * 
 */
public class StereoPlotDataQuickSeries extends StereoPlotDataSeries {
	private static final long serialVersionUID = -3223932608188847513L;

	protected int azimuthStep;
	protected int deviateStep;

	private double azimuthRange;
	private double azimuthStepSize;
	private double deviateRange;
	private double deviateStepSize;

	/**
	 * @param key
	 */
	public StereoPlotDataQuickSeries(String key) {
		super(key);
	}

	/**
	 * @param key
	 * @param type
	 * @param azimuthOffset
	 */
	public StereoPlotDataQuickSeries(String key, SymmetryType type,
			double azimuthOffset, int azimuthStep, int deviateStep) {
		super(key, type, azimuthOffset);
		this.azimuthStep = azimuthStep;
		this.deviateStep = deviateStep;

		switch (type) {
		case None:
			azimuthRange = 2 * Math.PI;
			break;
		case X_Symmetry:
		case Y_Symmetry:
			azimuthRange = Math.PI;
			break;
		case Center_Symmetry:
			azimuthRange = Math.PI / 2;
			break;
		default:
			break;
		}

		azimuthStepSize = azimuthRange / (azimuthStep - 1);
		deviateRange = Math.PI / 2;
		deviateStepSize = deviateRange / (deviateStep - 1);
	}

	public double getBestValue(double azimuth, double inclination) {
		azimuth += azimuthOffset;
		switch (type) {
		case None:
			azimuth = (azimuth < 0) ? azimuth + 2 * Math.PI : azimuth;
			azimuth = (azimuth > 2 * Math.PI) ? azimuth - 2 * Math.PI : azimuth;
			break;
		case X_Symmetry:
		case Y_Symmetry:
			azimuth = (azimuth < 0) ? azimuth + Math.PI : azimuth;
			azimuth = (azimuth > Math.PI) ? azimuth - Math.PI : azimuth;
			break;
		case Center_Symmetry:
			azimuth = (azimuth < 0) ? azimuth + 2 * Math.PI : azimuth;
			azimuth = (azimuth > Math.PI) ? azimuth - Math.PI : azimuth;
			azimuth = (azimuth > Math.PI / 2) ? azimuth - Math.PI / 2 : azimuth;
			break;
		default:
			break;
		}

		int azimuthIndex = (int) (azimuth / azimuthStepSize);
		int deviateIndex = (int) (inclination / deviateStepSize);

		double value = 0;
		try {
			StereoPlotDataItem Q00 = (StereoPlotDataItem) this.data
					.get(deviateIndex * azimuthStep + azimuthIndex);
			StereoPlotDataItem Q10 = (StereoPlotDataItem) this.data
					.get(deviateIndex * azimuthStep + azimuthIndex + 1);
			StereoPlotDataItem Q01 = (StereoPlotDataItem) this.data
					.get((deviateIndex + 1) * azimuthStep + azimuthIndex);
			StereoPlotDataItem Q11 = (StereoPlotDataItem) this.data
					.get((deviateIndex + 1) * azimuthStep + azimuthIndex + 1);

			double v00 = Q00.getValue();
			double v10 = Q10.getValue();
			double v01 = Q01.getValue();
			double v11 = Q11.getValue();

			double higherInclination = Q11.getDeviate();
			double lowerInclination = Q00.getDeviate();

			double higherAzimuth = Q11.getAzimuth();
			double lowerAzimuth = Q00.getAzimuth();

			double dHi = higherInclination - inclination;
			double dLi = inclination - lowerInclination;

			double dHa = higherAzimuth - azimuth;
			double dLa = azimuth - lowerAzimuth;

			double da = higherAzimuth - lowerAzimuth;
			double di = higherInclination - lowerInclination;

			value = v00 * dHa * dHi;
			value += v10 * dLa * dHi;
			value += v01 * dHa * dLi;
			value += v11 * dLa * dLi;
			value /= (da * di);

		} catch (Exception e) {
			return value;
		}
		return value;
	}
}
